# vim:ts=4:sw=4:noet:
""" 2D Simulator Renderer """

import wx
import time
import math
from c.ui.wxw.common import *
from c.simulator.simulator import Simulator

SIM_FPS = 15

if wx.Platform=="__WXMSW__":
	Paint = wx.BufferedPaintDC
else:
	Paint = wx.PaintDC

class SimCanvas(wx.Panel):

	def __init__(self, parent, mc):
		if wx.Platform=="__WXMAC__":
			wx.Panel.__init__(self, parent, -1)
		else:
			wx.Panel.__init__(self, parent, -1, style = wx.BORDER_SUNKEN)
		self.sim = Simulator(mc)
		self.mc = mc
		self.size = (100,100)
		self.saytext = ""
		self.drawTime = 0
		self.tstart = time.time()
		self.frames = 0
		self.oldt = time.time()
		self.timer = wx.Timer(self, -1)
		self.bgColour = wx.Colour(231, 235, 255)
		self.bg = wx.EmptyBitmap(100,100)
		self.drawBot = True
		self.Bind(wx.EVT_TIMER, self.OnTimer)
		self.Bind(wx.EVT_PAINT, self.OnDraw)
		self.Bind(wx.EVT_SIZE, self.OnSize)
		self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
		self.Bind(wx.EVT_RIGHT_UP, self.OnRightClick)
		self.timer.Start(1000/SIM_FPS)

	def __del__(self):
		self.sim.shutdown()

	def OnEraseBackground(self, event):
		pass
	
	def OnRightClick(self, event):
		if not hasattr(self, "setBackColour"):
			self.setBackColourId = wx.NewId()
			self.toggleRobotId = wx.NewId()
			self.Bind(wx.EVT_MENU, self.OnBackColour, id=self.setBackColourId)
			self.Bind(wx.EVT_MENU, self.OnToggleRobot, id=self.toggleRobotId)
		menu = wx.Menu()
		menu.Append(self.setBackColourId, "Set background colour")
		if self.drawBot:
			menu.Append(self.toggleRobotId, "Hide robot")
		else:
			menu.Append(self.toggleRobotId, "Show robot")
		self.PopupMenu(menu)
		menu.Destroy()

	def OnBackColour(self, event):
		dlg = wx.ColourDialog(self)
		dlg.GetColourData().SetChooseFull(True)
		if dlg.ShowModal() == wx.ID_OK:
			data = dlg.GetColourData()
			self.bgColour = data.GetColour().Get()
		dlg.Destroy()

	def OnToggleRobot(self, event):
		self.drawBot = not self.drawBot
		
	def OnSize(self, event):
		self.size = self.GetClientSize()
		if self.size[0]>50:
			self.sim.resetPos = [x/2 for x in self.size]
			self.sim.maxPos = self.size
		self.bg = wx.EmptyBitmap(self.size[0], self.size[1])
		self.sim.linesDrawn = 0
		event.Skip()

	def OnTimer(self, evt):
		newt = time.time()
		dt = newt-self.oldt
		self.oldt = newt
		self.sim.update(dt)
		if not self.sim.pbqueue.empty():
			self.saytext = self.sim.pbqueue.get()
			self.mc.view.logMessage("> %s\n" % self.saytext)
		self.Refresh()

	def OnDraw(self, evt):
		dstart = time.time()
		dc = Paint(self)
		try:
			gc = wx.GraphicsContext.Create(dc)
		except NotImplementedError:
			dc.DrawText("NONE FOR YOU", 25,25)
			return
		
		font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
		font.SetWeight(wx.BOLD)
		gc.SetFont(font)
		gc.SetBrush(wx.Brush(self.bgColour))

		path = gc.CreatePath()
		path.AddRectangle(0,0,self.size[0],self.size[1])

		gc.PushState()
		gc.FillPath(path)
		gc.PopState()
		
		# background -----
		if self.sim.needsReset:
			self.bg = wx.EmptyBitmap(self.size[0], self.size[1])
		memdc = wx.MemoryDC()
		memdc.SelectObject(self.bg)
		memgc = wx.GraphicsContext.Create(memdc)
		memgc.SetBrush(wx.Brush(self.bgColour))
		
		if self.sim.needsReset:
			self.sim.needsReset = False
			path = memgc.CreatePath()
			path.AddRectangle(0,0,self.size[0],self.size[1])
			memgc.PushState()
			memgc.FillPath(path)
			memgc.PopState()

		if len(self.sim.lines)>1:
			if self.sim.linesDrawn==0:
				prev = self.sim.lines[0][0]
			else:
				prev = self.sim.lines[self.sim.linesDrawn-1][0]
			while len(self.sim.lines)-self.sim.linesDrawn:
				point, col, width, down = self.sim.lines[self.sim.linesDrawn]
				if down:
					memgc.SetPen(wx.Pen(wx.Colour(*[x*255 for x in col]), width))
					memgc.StrokeLine(prev[0], prev[1], point[0], point[1])
				prev = point
				self.sim.linesDrawn += 1

		gc.DrawBitmap(self.bg, 0, 0, self.size[0], self.size[1])
		# background -----
			
		
		"""
		gc.PushState()
		if len(self.sim.lines)>1:
			prev = self.sim.lines[0][0]
			for point, col, width, down in self.sim.lines[1:]:
				if down:
					gc.SetPen(wx.Pen(wx.Colour(*[x*255 for x in col]), width))
					gc.StrokeLine(prev[0], prev[1], point[0], point[1])
				prev = point
			if down:
				gc.StrokeLine(prev[0], prev[1], self.sim.pos[0], self.sim.pos[1])
		gc.PopState()
		"""

		if self.drawBot:
			"""
			r = 20.0
			w = 7.0
			sa = math.radians(30)
			rw = math.sqrt(r*r + w*w)
			xc = self.sim.pos[0] - r*math.sin(self.sim.theta)
			yc = self.sim.pos[1] + r*math.cos(self.sim.theta)
			xl = self.sim.pos[0] - rw*math.sin(self.sim.theta+sa)
			yl = self.sim.pos[1] + rw*math.cos(self.sim.theta+sa)
			xr = self.sim.pos[0] - rw*math.sin(self.sim.theta-sa)
			yr = self.sim.pos[1] + rw*math.cos(self.sim.theta-sa)
			self.sim.lineSensor[0] = dc.GetPixel(xc,yc)!=self.bgColour
			self.sim.lineSensor[1] = dc.GetPixel(xl,yl)!=self.bgColour
			self.sim.lineSensor[2] = dc.GetPixel(xr,yr)!=self.bgColour
			#print self.sim.lineSensor
			"""
			w = self.sim.radius
			shd = gc.CreatePath()
			shd.AddArc(0,0,w/2 + 2,math.radians(0),math.radians(360))
			sqr = gc.CreatePath()
			sqr.AddArc(0,0,w/2,math.radians(0),math.radians(360))
			tri = gc.CreatePath()
			tri.AddArc(0,0,w*0.4,math.radians(-30),math.radians(210))
			tri2 = gc.CreatePath()
			tri2.AddArc(0,-4,w*0.2,math.radians(0),math.radians(360))

			bubble = gc.CreatePath()
			tw, th = gc.GetTextExtent(self.saytext)
			bw = max(0,tw-4)
			bubble.AddArc(15,-15,8,math.radians(90),math.radians(270))
			bubble.AddLineToPoint(15+bw,-23)
			bubble.AddArc(15+bw,-15,8,math.radians(270),math.radians(90))
			bubble.AddLineToPoint(15,-7)

			gc.PushState()
			gc.Translate(self.sim.pos[0], self.sim.pos[1])
			gc.Rotate(self.sim.theta)
			gc.SetBrush(wx.Brush(wx.Colour(0,0,0, 128)))
			gc.FillPath(shd)
			gc.SetBrush(wx.Brush(wx.Colour(255,255,255)))
			gc.FillPath(sqr)
			gc.SetBrush(wx.Brush(wx.Colour(0xFA,0x4E, 0x23)))
			gc.FillPath(tri)
			gc.FillPath(tri2)
			gc.PopState()
			
			if len(self.saytext)>0:
				gc.PushState()
				gc.Translate(self.sim.pos[0], self.sim.pos[1])
				gc.SetPen(wx.Pen(wx.Colour(0x33,0x33,0x33,64)))
				gc.SetBrush(wx.Brush(wx.Colour(0xFF,0xFF,0xFF,192)))
				gc.FillPath(bubble)
				gc.StrokePath(bubble)
				gc.DrawText(self.saytext, 13,-15-(th/2))
				gc.PopState()
		# measurements
		dtime = time.time()-dstart
		self.drawTime = (self.drawTime+dtime)/2.0
		if self.frames==0:
			self.tstart = time.time()-0.01
		self.frames += 1
		trun = time.time()-self.tstart
		fps = self.frames/trun
		#gc.DrawText("%0.1fms %0.1ffps" % (self.drawTime*1000, fps), 10,10)


